package com.levi.mall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.levi.enums.EnumUtil;
import com.levi.mall.mapper.OrderMapper;
import com.levi.mall.service.*;
import com.levi.pojo.*;
import com.levi.utils.BeanConvertUtil;
import com.levi.vo.OrderItemVo;
import com.levi.vo.OrderVo;
import com.levi.vo.ResponseVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shentong
 * @since 2022/4/5 11:42 AM
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
        implements OrderService {
    @Autowired
    private ShippingService shippingService;

    @Autowired
    private ProductService productService;

    @Autowired
    private CartService cartService;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private HashOperations<String, String, String> opsForHash;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseVo<OrderVo> create(Integer uid, Integer shippingId) {
        //查询收货地址，进行校验
        Shipping shipping = shippingService.getById(shippingId);
        if (shipping == null) {
            return ResponseVo.error(EnumUtil.SHIPPING_NOT_EXIST);
        }
        //根据uid查询出购车中选中的商品（是否有商品，库存是否够）
        List<Cart> cartList = cartService.listForCart(uid);
        List<Cart> selectedCartList = cartList.stream().filter(Cart::getProductSelected).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(selectedCartList)) {
            return ResponseVo.error(EnumUtil.CART_SELECTED_IS_EMPTY);
        }
        Set<Integer> selectedProductIdSet = selectedCartList.stream().map(Cart::getProductId).collect(Collectors.toSet());
        LambdaQueryWrapper<Product> ew = new LambdaQueryWrapper<>();
        ew.in(Product::getId,selectedProductIdSet);
        List<Product> productList = productService.list(ew);
        //构建map对象，方便下面操作
        Map<Integer, Product> productMap = productList.stream().collect(Collectors.toMap(Product::getId, product -> product));
        List<OrderItem> orderItemList = new ArrayList<>();
        Long orderNo = generateOrderNo();
        List<Product> updateProductList = new ArrayList<>();
        for (Cart cart : selectedCartList) {
            Product product = productMap.get(cart.getProductId());
            //判断商品是否存在
            if (product == null) {
                return ResponseVo.error(EnumUtil.PRODUCT_NOT_EXIST, "商品不存在，productId: " + cart.getProductId());
            }
            if (!EnumUtil.PRODUCT_STATUS_NOMAL.getCode().equals(product.getStatus())) {
                return ResponseVo.error(EnumUtil.PRODUCT_SOLD_OUT_OR_DELETED, "商品不是在售状态 商品名： " + product.getName());
            }
            //判断库存是否充足
            if (cart.getQuantity() > product.getStock()) {
                return ResponseVo.error(EnumUtil.PRODUCT_STOCK_ERROR, "商品库存不足, 商品名: " + product.getName());
            }
            OrderItem orderItem = buildOrderItem(uid,orderNo,product,cart.getQuantity());
            orderItemList.add(orderItem);
            product.setStock(product.getStock() - cart.getQuantity());
            updateProductList.add(product);
        }
        Order order = buildOrder(uid,orderNo,shippingId,orderItemList);
        // 计算总价  只计算选中的商品
        //生成订单
        boolean orderResult = this.save(order);
        if (!orderResult) {
            return ResponseVo.error(EnumUtil.ERROR);
        }
        //插入订单详情
        boolean orderItemResult = orderItemService.saveBatch(orderItemList);
        if (!orderItemResult) {
            return ResponseVo.error(EnumUtil.ERROR);
        }
        //批量扣减库存
        productService.updateBatchById(updateProductList);

        //更新购物车(选中的商品删除掉)
        for (Cart cart : selectedCartList) {
            cartService.deleteCart(uid, cart.getProductId());
        }
        //构建返回对象
        OrderVo orderVo = buildOrderVo(order,orderItemList,shipping);
        return ResponseVo.success(orderVo);
    }


    @Override
    public ResponseVo<PageInfo<OrderVo>> list(Integer uid, Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<Order> ewOrder = new LambdaQueryWrapper<>();
        ewOrder.eq(Order::getUserId, uid);
        PageHelper.startPage(pageNum, pageSize);
        List<Order> orderList = this.list(ewOrder);
        Set<Long> orderNoSet = orderList.stream().map(Order::getOrderNo).collect(Collectors.toSet());
        LambdaQueryWrapper<OrderItem> ewOrderItem = new LambdaQueryWrapper<>();
        ewOrderItem.in(!CollectionUtils.isEmpty(orderNoSet),OrderItem::getOrderNo, orderNoSet);
        List<OrderItem> orderItemList = orderItemService.list(ewOrderItem);
        Set<Integer> shippingIdSet = orderList.stream().map(Order::getShippingId).collect(Collectors.toSet());
        LambdaQueryWrapper<Shipping> ewShipping = new LambdaQueryWrapper<>();
        ewShipping.in(Shipping::getId, shippingIdSet);
        List<Shipping> shippingList = shippingService.list(ewShipping);
        Map<Long, List<OrderItem>> orderItemMap = orderItemList.stream().collect(Collectors.groupingBy(OrderItem::getOrderNo));
        Map<Integer, Shipping> shippingMap = shippingList.stream().collect(Collectors.toMap(Shipping::getId, shipping -> shipping));
        List<OrderVo> orderVoList = new ArrayList<>();
        for (Order order : orderList) {
            OrderVo orderVo = buildOrderVo(order, orderItemMap.get(order.getOrderNo()), shippingMap.get(order.getShippingId()));
            orderVoList.add(orderVo);
        }
        PageInfo<OrderVo> pageInfo = new PageInfo<>(orderVoList);
        return ResponseVo.success(pageInfo);
    }

    @Override
    public ResponseVo<OrderVo> detail(Integer uid, Long orderNo) {
        LambdaQueryWrapper<Order> ewOrder = new LambdaQueryWrapper<>();
        ewOrder.eq(Order::getUserId, uid)
                .eq(Order::getOrderNo, orderNo);
        Order order = this.getOne(ewOrder);
        LambdaQueryWrapper<OrderItem> ewOrderItem = new LambdaQueryWrapper<>();
        ewOrderItem.eq(OrderItem::getOrderNo, orderNo);
        List<OrderItem> orderItemList = orderItemService.list(ewOrderItem);
        Shipping shipping = shippingService.getById(order.getShippingId());
        OrderVo orderVo = buildOrderVo(order, orderItemList, shipping);
        return ResponseVo.success(orderVo);
    }

    @Override
    public ResponseVo cancel(Integer uid, Long orderNo) {
        LambdaQueryWrapper<Order> ew = new LambdaQueryWrapper<>();
        ew.eq(Order::getUserId, uid)
                .eq(Order::getOrderNo, orderNo);
        Order order = this.getOne(ew);
        if (order == null || !order.getUserId().equals(uid)) {
            return ResponseVo.error(EnumUtil.ORDER_NOT_EXIST);
        }
        if (!EnumUtil.ORDER_STATUS_NO_PAY.getCode().equals(order.getStatus())) {
            return ResponseVo.error(EnumUtil.ORDER_STATUS_ERROR);
        }
        order.setStatus(EnumUtil.ORDER_STATUS_CANCELED.getCode());
        order.setCloseTime(new Date());
        boolean result = this.updateById(order);
        if (!result) {
            return ResponseVo.error(EnumUtil.ERROR);
        }
        return ResponseVo.success();
    }


    @Override
    public void paid(Long orderNo) {
        LambdaQueryWrapper<Order> ew = new LambdaQueryWrapper<>();
        ew.eq(Order::getOrderNo, orderNo);
        Order order = this.getOne(ew);
        if (order == null) {
            //FIXME 可以加上钉钉告警，短信告警
            throw new RuntimeException(EnumUtil.ORDER_NOT_EXIST.getMsg() +"订单号："+orderNo);
        }
        if (!EnumUtil.ORDER_STATUS_NO_PAY.getCode().equals(order.getStatus())) {
            //FIXME 可以加上钉钉告警，短信告警
            throw new RuntimeException(EnumUtil.ORDER_STATUS_ERROR.getMsg() +"订单号："+order.getOrderNo());
        }
        order.setStatus(EnumUtil.ORDER_STATUS_PAID.getCode());
        order.setPaymentTime(new Date());
        this.updateById(order);
    }

    /**
     * 构建orderVo
     * @param order
     * @param orderItemList
     * @param shipping
     * @return
     */
    private OrderVo buildOrderVo(Order order, List<OrderItem> orderItemList,Shipping shipping) {
        OrderVo orderVo = new OrderVo();
        BeanUtils.copyProperties(order, orderVo);
        List<OrderItemVo> orderItemVoList = BeanConvertUtil.listConvert(orderItemList, OrderItemVo.class);
        orderVo.setOrderItemvoList(orderItemVoList);
        orderVo.setShippingId(shipping.getId());
        orderVo.setShippingVo(shipping);
        return orderVo;
    }

    /**
     * 构建order对象
     * @param uid
     * @param orderNo
     * @param shippingId
     * @param orderItemList
     * @return
     */
    private Order buildOrder(Integer uid, Long orderNo, Integer shippingId, List<OrderItem> orderItemList) {
        BigDecimal payment = orderItemList.stream()
                .map(OrderItem::getTotalPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        Order order = new Order();
        order.setUserId(uid);
        order.setOrderNo(orderNo);
        order.setStatus(EnumUtil.ORDER_STATUS_NO_PAY.getCode());
        order.setShippingId(shippingId);
        order.setPaymentType(EnumUtil.PAY_TYPE_ON_LINE.getCode());
        order.setPayment(payment);
        return order;
    }

    /**
     * 生成orderNo
     * @return
     */
    private Long generateOrderNo() {
        return System.currentTimeMillis() + new Random().nextInt(999);
    }

    /**
     * 构建orderItem对象
     * @param uid
     * @param orderNo
     * @param product
     * @param quantity
     * @return
     */
    private OrderItem buildOrderItem(Integer uid, Long orderNo, Product product, Integer quantity) {
        OrderItem orderItem = new OrderItem();
        orderItem.setUserId(uid);
        orderItem.setOrderNo(orderNo);
        orderItem.setProductId(product.getId());
        orderItem.setProductName(product.getName());
        orderItem.setProductImage(product.getMainImage());
        orderItem.setCurrentUnitPrice(product.getPrice());
        orderItem.setQuantity(quantity);
        orderItem.setTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(quantity)));
        return orderItem;
    }
}
